package com.blue.http.util;

import java.io.File;
import java.io.UnsupportedEncodingException;
import java.net.InetSocketAddress;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;

import javax.activation.MimetypesFileTypeMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSONObject;
import com.blue.http.config.ErrorConfig;
import com.blue.http.message.HttpResponse;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpHeaderValues;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpUtil;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.codec.http.cookie.Cookie;
import io.netty.handler.codec.http.cookie.DefaultCookie;
import io.netty.handler.codec.http.cookie.ServerCookieEncoder;
import io.netty.util.CharsetUtil;
import io.netty.util.Version;

/**
 * Http服务器工具类
 * 
 * @author zhengj
 * @since 1.0 2016年9月4日
 */
public class HttpServerUtil
{
	private static Logger logger = LoggerFactory.getLogger(HttpServerUtil.class);

	public static final String HTTP_DATE_FORMAT = "EEE, dd MMM yyyy HH:mm:ss zzz";
	public static final String HTTP_DATE_GMT_TIMEZONE = "GMT";
	public static final int HTTP_CACHE_SECONDS = 60;

	private static MimetypesFileTypeMap mimeMap = new MimetypesFileTypeMap();

	private HttpServerUtil()
	{
	}
	
	public static void sendHtml(ChannelHandlerContext ctx, HttpRequest request, HttpResponse message)
	{
		FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
		String contentType = message.getContentType();
		if (contentType == null || contentType.isEmpty())
			contentType = HttpResponse.DEFAULT_CONTENT_TYPE;
		response.headers().add(HttpHeaderNames.CONTENT_TYPE, contentType);
		setCookie(response, message);
		if (HttpUtil.isKeepAlive(request))
		{
			response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
		}
		
		String result = null;
		if (message.getCode() == ErrorConfig.SUCCESS)
		{
			result = message.getResult();
		}
		else
		{
			JSONObject object = new JSONObject();
			object.put("code", message.getCode());
			object.put("msg", message.getMsg());
			object.put("extmsg", message.getExtmsg());
			result = object.toJSONString();
		}
		if (result == null || result.isEmpty())
		{
			JSONObject object = new JSONObject();
			object.put("code", ErrorConfig.SUCCESS);
			object.put("msg", ErrorConfig.getInstance().get(ErrorConfig.SUCCESS));
			result = object.toJSONString();
		}
		
		ByteBuf buf = Unpooled.copiedBuffer(result, CharsetUtil.UTF_8);
		response.content().writeBytes(buf);
		buf.release();
		ChannelFuture future = ctx.writeAndFlush(response);
		if (!HttpUtil.isKeepAlive(request))
		{
			future.addListener(ChannelFutureListener.CLOSE);
		}
	}
	
	public static void sendRedirect(ChannelHandlerContext ctx, String uri)
	{
		FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.FOUND);
		HttpHeaders headers = response.headers();
		headers.set(HttpHeaderNames.LOCATION, uri);
		ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
	}
	
	public static void sendError(ChannelHandlerContext ctx, HttpResponseStatus status)
	{
		String ver = "4.1.4 Final";
		Version version = Version.identify().get("netty-common");
		if (version != null)
			ver = version.artifactVersion();
		
		FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, status);
		HttpHeaders headers = response.headers();
		headers.set(HttpHeaderNames.CONTENT_TYPE, "text/html; charset=UTF-8");
		
		StringBuilder sb = new StringBuilder(256);
		sb.append("<!doctype html>\r\n<html>\r\n<head>\r\n<meta charset=\"UTF-8\"/>\r\n<title>Error</title>\r\n</head>\r\n<body>\r\n");
		sb.append("<center><h1>").append(status.toString()).append("</h1></center><hr/><h4>Netty");
		sb.append(ver).append("</h4>");		
		sb.append("</body>\r\n</html>\r\n");
		ByteBuf buf = Unpooled.copiedBuffer(sb, CharsetUtil.UTF_8);
		response.content().writeBytes(buf);
		buf.release();
		ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
	}

	public static void setCookie(FullHttpResponse response, HttpResponse message)
	{
		if (message.getCookie() == null || message.getCookie().isEmpty())
			return;

		ServerCookieEncoder encoder = ServerCookieEncoder.STRICT;
		HttpHeaders headers = response.headers();
		for (Map.Entry<String, String> entry : message.getCookie().entrySet())
		{
			Cookie cookie = new DefaultCookie(entry.getKey(), entry.getValue());
			cookie.setPath("/");
			cookie.setMaxAge(3600 * 24 * 30);
			cookie.setHttpOnly(false);
			String strCookie = encoder.encode(cookie);
			headers.add(HttpHeaderNames.SET_COOKIE, strCookie);
		}
	}

	public static void send100Continue(ChannelHandlerContext ctx)
	{
		FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.CONTINUE);
		ctx.writeAndFlush(response);
	}

	public static void sendNotModified(ChannelHandlerContext ctx)
	{
		FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.NOT_MODIFIED);
		setDateHeader(response);
		ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
	}

	public static void setDateHeader(FullHttpResponse response)
	{
		SimpleDateFormat dateFormatter = new SimpleDateFormat(HTTP_DATE_FORMAT, Locale.US);
		dateFormatter.setTimeZone(TimeZone.getTimeZone(HTTP_DATE_GMT_TIMEZONE));

		Calendar time = new GregorianCalendar();
		response.headers().set(HttpHeaderNames.DATE, dateFormatter.format(time.getTime()));
	}

	public static void setDateAndCacheHeaders(io.netty.handler.codec.http.HttpResponse response, File file)
	{
		SimpleDateFormat dateFormatter = new SimpleDateFormat(HTTP_DATE_FORMAT, Locale.US);
		dateFormatter.setTimeZone(TimeZone.getTimeZone(HTTP_DATE_GMT_TIMEZONE));

		Calendar time = new GregorianCalendar();
		response.headers().set(HttpHeaderNames.DATE, dateFormatter.format(time.getTime()));

		time.add(Calendar.SECOND, HTTP_CACHE_SECONDS);
		response.headers().set(HttpHeaderNames.EXPIRES, dateFormatter.format(time.getTime()));
		response.headers().set(HttpHeaderNames.CACHE_CONTROL, "private, max-age=" + HTTP_CACHE_SECONDS);
		response.headers().set(HttpHeaderNames.LAST_MODIFIED, dateFormatter.format(new Date(file.lastModified())));
	}

	public static void setContentType(io.netty.handler.codec.http.HttpResponse response, String filename)
	{
		String mimeType = mimeMap.getContentType(filename);
		//logger.info("文件：{} - Content-Type：{}", filename, mimeType);
		response.headers().set(HttpHeaderNames.CONTENT_TYPE, mimeType);
	}

	public static void setDownloadFilename(io.netty.handler.codec.http.HttpResponse response, String filename)
	{
		try
		{
			filename = new String(filename.getBytes("UTF-8"), "ISO8859-1");
		}
		catch (UnsupportedEncodingException e)
		{
			e.printStackTrace();
		}
		response.headers().set(HttpHeaderNames.CONTENT_DISPOSITION, "attachment; filename=" + filename);
	}
	
	public static String getIp(HttpHeaders headers, Channel channel)
	{
		String ip = headers.get("x-forwarded-for");
		if (ip == null || ip.isEmpty() || ip.equalsIgnoreCase("unknown"))
		{
			ip = headers.get("Proxy-Client-IP");
		}
		if (ip == null || ip.isEmpty() || ip.equalsIgnoreCase("unknown"))
		{
			ip = headers.get("WL-Proxy-Client-IP");
		}
		if (ip == null || ip.isEmpty() || ip.equalsIgnoreCase("unknown"))
		{
			InetSocketAddress address = (InetSocketAddress)channel.remoteAddress();
			ip = address.getAddress().getHostAddress();
		}
		return ip;
	}

	/**
	 * 是否文本提交
	 *
	 * @param request
	 * @return
	 */
	public static boolean isPostText(HttpRequest request)
	{
		CharSequence type = HttpUtil.getMimeType(request);
		if (type == null || type.length() == 0)
			return true;

		String mimeType = type.toString();
		if ("application/x-www-form-urlencoded".equals(mimeType))
			return true;
		if ("application/json".equals(mimeType))
			return true;
		if (mimeType.startsWith("text/"))
			return true;

		return false;
	}
	
}
